package com.ruubypay.biz.utils.mac;

import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import javax.crypto.Cipher;
import javax.crypto.Mac;
import javax.crypto.NoSuchPaddingException;
import javax.crypto.SecretKey;
import javax.crypto.spec.IvParameterSpec;
import javax.crypto.spec.SecretKeySpec;
import java.lang.reflect.Field;
import java.security.Key;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.*;

public class HMAC {

    public static Logger logger = LoggerFactory.getLogger(HMAC.class);

    private static String MAIN_KEY = "BEE62B7E1DB438CDC77758DEB07061038D4BFAB7";
    private static String IV = "0000000000000000";
    private static String verify_mac = "1";       //  1-验mac  0-不验

    /**
     * 验证报文HMAC
     *
     * @param macKey    HMAC密钥
     * @param dictParam 参数字典
     * @param hmac      客户端上送的mac值
     * @return
     */
    public static int VerifyHMAC(String macKey, HashMap<String, String> dictParam, String hmac) {
        if (Objects.equals(verify_mac, "0")) {
            return 0;
        }
        if (macKey.length() != 40) {
            return 1;    //makey 长度不足
        }
        if (!dictParam.containsKey("ts")) {
            return 2;    //缺少时间戳
        }

        String hash = CalcHMAC(macKey, dictParam);
//        logger.info(" user or mainkey " + macKey);
//        logger.info(" dictparam " + dictParam);
//        logger.info(" my " + hash);
//        logger.info(" his " + hmac);
        return hash.equals(hmac.toUpperCase()) ? 0 : 4;      // 4 mac校验不匹配
    }


    /**
     * 计算HMAC校验
     *
     * @param macKey
     * @param dictParam 参与校验的数据字典，所有需要提交的数据均要计算，注意添加一个"ts"字段，内容为当前时间戳（通过本类中的 getUnixTimeStamp 获取）
     * @return
     */
    public static String CalcHMAC(String macKey, HashMap<String, String> dictParam) {
        StringBuilder sb = new StringBuilder();
        SortedSet<String> keys = new TreeSet<>(String.CASE_INSENSITIVE_ORDER);
        keys.addAll(dictParam.keySet());

        for (String key : keys) {
            sb.append(key);
            sb.append(dictParam.get(key));
            sb.append("||");
        }
//        logger.debug(" 商户密钥：" + macKey);
//        logger.debug(" 待签名字符串：" + sb.toString());
        SecretKeySpec keySpec = new SecretKeySpec(hexStringToByte(macKey), "HmacSHA1");
        Mac mac;
        try {
            mac = Mac.getInstance("HmacSHA1");
            mac.init(keySpec);
            byte[] result = mac.doFinal(sb.toString().getBytes("UTF-8"));
//            logger.debug("     签名结果：" + bytesToHexString(result));
            return bytesToHexString(result);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取Unix时间戳
     *
     * @return
     */
    public static String getUnixTimeStamp() {
        return String.valueOf(System.currentTimeMillis() / 1000);
    }

    /**
     * DES解密
     *
     * @param key     密钥
     * @param IV      填充
     * @param hexText 待解密参数
     * @return 解密之后明文
     */
    public static String DESDecrypt(String key, String IV, String hexText) {
        try {
            Cipher desCipher = Cipher.getInstance("DES/CBC/Nopadding");
            Key deskey = new SecretKeySpec(hexStringToByte(key), 0, key.length() / 2, "DES");
            IvParameterSpec iv = new IvParameterSpec(hexStringToByte(IV));
            desCipher.init(Cipher.DECRYPT_MODE, deskey, iv);
            return bytesToHexString(desCipher.doFinal(hexStringToByte(hexText)));
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }

    /**
     * DES加密
     *
     * @param key     密钥
     * @param IV      填充
     * @param hexText 待加密参数
     * @return 加密后密文
     */
    public static String DESEncrypt(String key, String IV, String hexText) {
        try {
            Cipher desCipher = Cipher.getInstance("DES/CBC/Nopadding");
            Key deskey = new SecretKeySpec(hexStringToByte(key), 0, key.length() / 2, "DES");
            IvParameterSpec iv = new IvParameterSpec(hexStringToByte(IV));
            desCipher.init(Cipher.ENCRYPT_MODE, deskey, iv);
            return bytesToHexString(desCipher.doFinal(hexStringToByte(hexText)));
        } catch (Exception ex) {
            ex.printStackTrace();
            return null;
        }
    }


    /**
     * 把16进制字符串转换成字节数组
     *
     * @param hex
     * @return
     */
    private static byte[] hexStringToByte(String hex) {
        int len = (hex.length() / 2);
        byte[] result = new byte[len];
        char[] achar = hex.toCharArray();
        for (int i = 0; i < len; i++) {
            int pos = i * 2;
            result[i] = (byte) (toByte(achar[pos]) << 4 | toByte(achar[pos + 1]));
        }
        return result;
    }

    private static byte toByte(char c) {
        byte b = (byte) "0123456789ABCDEF".indexOf(c);
        return b;
    }

    /**
     * 把字节数组转换成16进制字符串
     *
     * @param bArray
     * @return
     */
    private static String bytesToHexString(byte[] bArray) {
        if (bArray == null) {
            return "";
        }
        StringBuilder sb = new StringBuilder(bArray.length);
        String sTemp;
        for (byte aBArray : bArray) {
            sTemp = Integer.toHexString(0xFF & aBArray);
            if (sTemp.length() < 2)
                sb.append(0);
            sb.append(sTemp.toUpperCase());
        }
        return sb.toString();
    }

    //将对象中的属性加入参数字典
    public static HashMap<String, String> ConvertObjToMap(Object obj) {
        HashMap<String, String> reMap = new HashMap<String, String>();
        if (obj == null)
            return null;
        Field[] fields = obj.getClass().getDeclaredFields();
        try {
            for (Field field : fields) {
                try {
                    if (!field.getName().equals("mac")) {
                        Field f = obj.getClass().getDeclaredField(field.getName());
                        f.setAccessible(true);
                        String o = "";
                        if (f.get(obj) == null) {
                            o = "";
                        } else {
                            o = f.get(obj).toString();
                        }
                        reMap.put(field.getName(), o);
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        }
        return reMap;
    }


    /// <summary>
    /// 生成新的HMAC KEY
    /// </summary>
    /// <param name="usercode">用户ID</param>
    /// <returns>长度为40的十六进制字符串 （转换为byte数组后为20字节，160bit）</returns>
    public static String GetNewHMACKey(String UserPhoneNo) {
        String str = UserPhoneNo + UUID.randomUUID().toString();
        byte[] enk = hex(str);
        byte[] encoded = encryptMode(enk, MAIN_KEY.getBytes());
        String HMACKey = bytesToHexString(encoded);
        HMACKey = HMACKey.toUpperCase().substring(0, 40);
        return HMACKey;
    }

    /**
     * args在java中调用sun公司提供的3DES加密解密算法时，需要使
     * 用到$JAVA_HOME/jre/lib/目录下如下的4个jar包：
     * jce.jar
     * security/US_export_policy.jar
     * security/local_policy.jar
     * ext/sunjce_provider.jar
     */
    public static byte[] encryptMode(byte[] keybyte, byte[] src) {
        String Algorithm = "DESede"; //定义加密算法,可用 DES,DESede,Blowfish
        try {
            //生成密钥
            SecretKey deskey = new SecretKeySpec(keybyte, Algorithm);
            //加密
            Cipher c1 = Cipher.getInstance(Algorithm);
            c1.init(Cipher.ENCRYPT_MODE, deskey);
            return c1.doFinal(src);//在单一方面的加密或解密
        } catch (NoSuchAlgorithmException e1) {
            e1.printStackTrace();
        } catch (NoSuchPaddingException e2) {
            e2.printStackTrace();
        } catch (Exception e3) {
            e3.printStackTrace();
        }
        return null;
    }

    //转换成十六进制字符串
    public static String byte2Hex(byte[] b) {
        String hs = "";
        String stmp = "";
        for (int n = 0; n < b.length; n++) {
            stmp = (Integer.toHexString(b[n] & 0XFF));
            if (stmp.length() == 1) {
                hs = hs + "0" + stmp;
            } else {
                hs = hs + stmp;
            }
            if (n < b.length - 1) hs = hs + ":";
        }
        return hs.toUpperCase();
    }

    public static byte[] hex(String username) {
        String key = "test"; //关键字
        String f = DigestUtils.md5Hex(username + key);
        byte[] bkeys = new String(f).getBytes();
        byte[] enk = new byte[24];
        for (int i = 0; i < 24; i++) {
            enk[i] = bkeys[i];
        }
        return enk;
    }

    /**
     * sha1值计算<p>
     *
     * @return sha1值
     */
    public static String getSHA1(String decript) {
        try {
            MessageDigest digest = MessageDigest
                    .getInstance("SHA-1");
            digest.update(decript.getBytes());
            byte messageDigest[] = digest.digest();
            // Create Hex String
            StringBuilder hexString = new StringBuilder();
            // 字节数组转换为 十六进制 数
            for (byte aMessageDigest : messageDigest) {
                String shaHex = Integer.toHexString(aMessageDigest & 0xFF);
                if (shaHex.length() < 2) {
                    hexString.append(0);
                }
                hexString.append(shaHex);
            }
            return hexString.toString();

        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return "";
    }

}
